package com.xy.xyaicpzs.util;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * 大乐透中奖规则计算器
 * 根据预测号码和开奖号码计算中奖等级和奖金
 */
@Slf4j
public class DltPrizeCalculator {

    /**
     * 中奖结果
     */
    @Data
    public static class PrizeResult {
        /** 中奖等级 */
        private String prizeLevel;
        /** 奖金（元） */
        private Long bonus;
        /** 前区命中个数 */
        private int frontMatches;
        /** 后区命中个数 */
        private int backMatches;
        
        public PrizeResult(String prizeLevel, Long bonus, int frontMatches, int backMatches) {
            this.prizeLevel = prizeLevel;
            this.bonus = bonus;
            this.frontMatches = frontMatches;
            this.backMatches = backMatches;
        }
    }

    /**
     * 计算大乐透中奖结果
     * 
     * @param predictNumbers 预测号码数组，格式：[前区5个号码, 后区2个号码]
     * @param drawNumbers 开奖号码数组，格式：[前区5个号码, 后区2个号码]
     * @return 中奖结果
     */
    public static PrizeResult calculatePrize(Integer[] predictNumbers, Integer[] drawNumbers) {
        if (predictNumbers == null || drawNumbers == null) {
            throw new IllegalArgumentException("预测号码和开奖号码不能为空");
        }
        
        if (predictNumbers.length != 7 || drawNumbers.length != 7) {
            throw new IllegalArgumentException("号码数组长度必须为7（前区5个+后区2个）");
        }

        // 分离前区和后区号码
        Integer[] predictFront = Arrays.copyOfRange(predictNumbers, 0, 5);
        Integer[] predictBack = Arrays.copyOfRange(predictNumbers, 5, 7);
        Integer[] drawFront = Arrays.copyOfRange(drawNumbers, 0, 5);
        Integer[] drawBack = Arrays.copyOfRange(drawNumbers, 5, 7);

        // 计算前区命中个数
        int frontMatches = calculateMatches(predictFront, drawFront);
        
        // 计算后区命中个数
        int backMatches = calculateMatches(predictBack, drawBack);

        log.debug("前区命中{}个，后区命中{}个", frontMatches, backMatches);

        // 根据中奖规则判断奖级
        String prizeLevel = determinePrizeLevel(frontMatches, backMatches);
        Long bonus = calculateBonus(prizeLevel);

        return new PrizeResult(prizeLevel, bonus, frontMatches, backMatches);
    }

    /**
     * 计算两个号码数组的匹配个数
     */
    private static int calculateMatches(Integer[] predict, Integer[] draw) {
        Set<Integer> drawSet = new HashSet<>(Arrays.asList(draw));
        int matches = 0;
        
        for (Integer number : predict) {
            if (number != null && drawSet.contains(number)) {
                matches++;
            }
        }
        
        return matches;
    }

    /**
     * 根据前区和后区命中个数判断中奖等级
     */
    private static String determinePrizeLevel(int frontMatches, int backMatches) {
        // 根据大乐透中奖规则图片判断
        if (frontMatches == 5 && backMatches == 2) {
            return "一等奖";
        } else if (frontMatches == 5 && backMatches == 1) {
            return "二等奖";
        } else if (frontMatches == 5 && backMatches == 0) {
            return "三等奖";
        } else if (frontMatches == 4 && backMatches == 2) {
            return "四等奖";
        } else if (frontMatches == 4 && backMatches == 1) {
            return "五等奖";
        } else if (frontMatches == 4 && backMatches == 0) {
            return "六等奖";
        } else if (frontMatches == 3 && backMatches == 2) {
            return "七等奖";
        } else if ((frontMatches == 3 && backMatches == 1) || 
                   (frontMatches == 2 && backMatches == 2)) {
            return "八等奖";
        } else if ((frontMatches == 3 && backMatches == 0) || 
                   (frontMatches == 2 && backMatches == 1) || 
                   (frontMatches == 1 && backMatches == 2) || 
                   (frontMatches == 0 && backMatches == 2)) {
            return "九等奖";
        } else {
            return "未中奖";
        }
    }

    /**
     * 根据中奖等级计算奖金（基本投注2元）
     */
    private static Long calculateBonus(String prizeLevel) {
        switch (prizeLevel) {
            case "一等奖":
                return 10000000L; // 1000万元（浮动奖金，这里设置为最高奖金）
            case "二等奖":
                return 5000000L;  // 500万元（浮动奖金）
            case "三等奖":
                return 10000L;    // 1万元
            case "四等奖":
                return 3000L;     // 3000元
            case "五等奖":
                return 300L;      // 300元
            case "六等奖":
                return 200L;      // 200元
            case "七等奖":
                return 100L;      // 100元
            case "八等奖":
                return 15L;       // 15元
            case "九等奖":
                return 5L;        // 5元
            default:
                return 0L;        // 未中奖
        }
    }

    /**
     * 验证号码格式是否正确
     */
    public static boolean validateNumbers(Integer[] numbers) {
        if (numbers == null || numbers.length != 7) {
            return false;
        }

        // 验证前区号码（1-35）
        for (int i = 0; i < 5; i++) {
            if (numbers[i] == null || numbers[i] < 1 || numbers[i] > 35) {
                return false;
            }
        }

        // 验证后区号码（1-12）
        for (int i = 5; i < 7; i++) {
            if (numbers[i] == null || numbers[i] < 1 || numbers[i] > 12) {
                return false;
            }
        }

        // 验证前区号码不能重复
        Set<Integer> frontSet = new HashSet<>();
        for (int i = 0; i < 5; i++) {
            if (!frontSet.add(numbers[i])) {
                return false; // 有重复
            }
        }

        // 验证后区号码不能重复
        if (numbers[5].equals(numbers[6])) {
            return false;
        }

        return true;
    }

    /**
     * 格式化号码显示
     */
    public static String formatNumbers(Integer[] numbers) {
        if (numbers == null || numbers.length != 7) {
            return "无效号码";
        }

        StringBuilder sb = new StringBuilder();
        
        // 前区号码
        sb.append("前区: ");
        for (int i = 0; i < 5; i++) {
            if (i > 0) sb.append(" ");
            sb.append(String.format("%02d", numbers[i]));
        }
        
        // 后区号码
        sb.append(" | 后区: ");
        for (int i = 5; i < 7; i++) {
            if (i > 5) sb.append(" ");
            sb.append(String.format("%02d", numbers[i]));
        }
        
        return sb.toString();
    }
}
